package middles

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"{{.ProjectName}}/config"
	initplugs "{{.ProjectName}}/init_plugs"
	"{{.ProjectName}}/utils"
	"io"
	"time"

	"github.com/gin-gonic/gin"
)

var (
	fginConfig config.Config
)

func AddMiddleWare(r *gin.Engine) {
	fginConfig = config.Cfg
	middleWareLs := []gin.HandlerFunc{recoverMiddleWare(), fginRateLimiterMiddleware(), fginCircuitBreakerMiddleware()}
	if (fginConfig.Log != config.Log{}) {
		// 如果日志配置不为空，则自动增加入gin中间件
		middleWareLs = append(middleWareLs, logMiddleware())
	}
	// 将响应体暴露出去
	middleWareLs = append(middleWareLs, fginResponseMiddleware())
	r.Use(middleWareLs...)
}

// 日志中间件
func logMiddleware() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		nowTime := time.Now()
		// 记录请求日志
		bodyParamsB, _ := io.ReadAll(ctx.Request.Body)
		// body只能读取一次，所以要重新写回
		ctx.Request.Body = io.NopCloser(bytes.NewBuffer(bodyParamsB))
		ctx.Next()
		// 耗时
		consTime := time.Since(nowTime)
		// 处理为紧凑的json
		paramsMap := map[string]any{}
		_ = json.Unmarshal(bodyParamsB, &paramsMap)
		bodyParams, _ := json.Marshal(paramsMap)
		logInfo := fmt.Sprintf("ip:%s, code: %v, cons:%v, method:%s, uri:%s, form:%v, body:%s", ctx.ClientIP(), ctx.Writer.Status(), consTime, ctx.Request.Method, ctx.Request.URL, ctx.Request.Form, bodyParams)
		defer func() {
			if err := recover(); err != nil {
				// 捕获程序异常
				logErr := fmt.Sprintf("code: 500, cons:%v, method:%s, uri:%s,form:%v, body:%s; err: %v", consTime, ctx.Request.Method, ctx.Request.URL, ctx.Request.Form, bodyParams, err)
				initplugs.LogSuger.Error(logErr)
				utils.ReturnJson(ctx, 500, nil, errors.New("服务异常,稍后再试"))
				// 可以增加一个邮件报警,机器人报警
			} else {
				if ctx.Request.URL.Path == "/ping" {
					// 如果是探针接口，不记录入日志
				} else {
					initplugs.LogSuger.Info(logInfo)
				}
			}
		}()
	}
}

// 异常抓取中间件
func recoverMiddleWare() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				if (fginConfig.Log == config.Log{} || initplugs.LogSuger == nil) {
					fmt.Println(err)
				} else {
					initplugs.LogSuger.Error(err)
				}
			}
		}()
		ctx.Next()
	}
}

// 定义一个自定义的 ResponseWriter，以便我们可以捕获响应数据
type FginResponseWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (w *FginResponseWriter) Write(b []byte) (int, error) {
	// 捕获响应数据到 buffer 中
	w.body.Write(b)
	// 调用原始的 Write 方法
	return w.ResponseWriter.Write(b)
}

// 中间件函数，用于创建 CustomResponseWriter,将响应体记录到上下文
func fginResponseMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 创建一个自定义的 ResponseWriter
		customWriter := &FginResponseWriter{
			ResponseWriter: ctx.Writer,
			body:           bytes.NewBufferString(""),
		}
		// 将自定义 Writer 替换默认的 ResponseWriter
		ctx.Writer = customWriter
		// 继续处理请求
		ctx.Next()
		// 将自定义 Writer 存储到上下文中，以便后续中间件访问
		ctx.Set("fginResponse", customWriter)
	}
}

// 限流器中间件
func fginRateLimiterMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		if err := initplugs.RateLimiter.Allow(); err != nil {
			initplugs.LogSuger.Info(ctx.Request.URL.Path + initplugs.RateErrMsg)
			utils.ReturnJson(ctx, initplugs.RateCode, "", errors.New(ctx.Request.URL.Path+initplugs.RateErrMsg))
			ctx.Abort()
			return
		}
		ctx.Next()
	}
}

// 熔断中间件
func fginCircuitBreakerMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		if err := initplugs.CircuitBreaker.Allow(); err != nil {
			initplugs.LogSuger.Info(ctx.Request.URL.Path + initplugs.CircuitErrMsg)
			utils.ReturnJson(ctx, initplugs.CircuitCode, "", errors.New(ctx.Request.URL.Path+initplugs.CircuitErrMsg))
			ctx.Abort()
			return
		}
		ctx.Next()
		// 500之间状态码，定义为可熔断
		if ctx.Writer.Status() < 600 || ctx.Writer.Status() >= 500 {
			// 标记失败
			initplugs.CircuitBreaker.MarkFailed()
		} else {
			// 标记成功
			initplugs.CircuitBreaker.MarkSuccess()
		}
	}
}
